// We can't change Telegram API
#![allow(clippy::too_many_arguments)]

use url::Url;

use crate::{errors::AsResponseParameters, payloads::*, requests::Request, types::*};

/// Telegram Bot API client.
///
/// This trait is implemented by all bots & bot adaptors.
///
/// ## Calling Telegram Bot API methods
///
/// To call Telegram's methods you first need to get a [`Bot`] instance or any
/// other type which implement this trait.
///
/// Then you can simply call the method you want and pass required parameters to
/// it. Optional parameters can be supplied by calling setters (like
/// `parse_mode` in the example below). Lastly, you need to `.await` the request
/// created in previous steps, to actually send it to telegram and wait for the
/// response.
///
/// ```
/// # async {
/// # let chat_id = ChatId(-1);
/// use teloxide_core::{
///     prelude::*,
///     types::{ChatId, ParseMode},
/// };
///
/// // Bot implements `Requester`
/// let bot = Bot::new("TOKEN");
///
/// // Required parameters are supplied to the `Requester` methods:
/// bot.send_message(chat_id, "<b>Text</b>")
///     // Optional parameters can be supplied by calling setters
///     .parse_mode(ParseMode::Html)
///     // To send request to telegram you need to `.await` the request
///     .await?;
/// # Ok::<_, teloxide_core::RequestError>(())
/// # };
/// ```
///
/// ## Adaptors
///
/// Similarly to how [`Iterator`] has iterator adaptors ([`FlatMap`],
/// [`Filter`], etc) that wrap an [`Iterator`] and alter its behaviour, Teloxide
/// has a similar story with `Requester`.
///
/// [`adaptors`] module provides a handful of `Requester` adaptors that can be
/// created via [`RequesterExt`] methods. For example using [`.parse_mode(...)`]
/// on a bot will wrap it in [`DefaultParseMode`] adaptor which sets the parse
/// mode to a default value:
///
/// ```rust
/// # async {
/// # let chat_id = ChatId(-1);
/// use teloxide_core::{
///     prelude::*,
///     types::{ChatId, ParseMode},
/// };
///
/// let bot = Bot::new("TOKEN")
///     // Wrap the bot in an adaptor
///     .parse_mode(ParseMode::Html);
///
/// // This will use `ParseMode::Html`
/// bot.send_message(chat_id, "<b>Text</b>").await?;
///
/// // This will use `ParseMode::MarkdownV2`
/// bot.send_message(chat_id, "**Text**").parse_mode(ParseMode::MarkdownV2).await?;
/// # Ok::<_, teloxide_core::RequestError>(())
/// # };
/// ```
///
/// Note that just as with iterators, adaptors change type:
///
/// ```compile_fail
/// # use teloxide_core::{prelude::*, types::{ChatId, ParseMode}};
/// let bot: Bot = Bot::new("TOKEN").parse_mode(ParseMode::Html);
/// ```
/// ```rust
/// # use teloxide_core::{prelude::*, types::{ChatId, ParseMode}, adaptors::DefaultParseMode};
/// let bot: DefaultParseMode<Bot> = Bot::new("TOKEN").parse_mode(ParseMode::Html);
/// ```
///
/// Because of this it's oftentimes more convinient to have a type alias:
///
/// ```rust,no_run
/// # #[cfg(feature = "throttle")] {
/// # use teloxide_core::{adaptors::{DefaultParseMode, Throttle}, requests::RequesterExt, types::ParseMode};
/// type Bot = DefaultParseMode<Throttle<teloxide_core::Bot>>;
///
/// let bot: Bot = teloxide_core::Bot::new("TOKEN")
///     .throttle(<_>::default())
///     .parse_mode(ParseMode::Html);
/// # let _ = bot;
/// # };
/// ```
///
/// Also note that most adaptors require specific cargo features to be enabled.
/// For example, to use [`Throttle`] you need to enable `throttle` feature in
/// your `Cargo.toml`:
///
/// ```toml
/// teloxide_core = { version = "...", features = ["throttle"] }
/// ```
///
/// Refer to adaptor's documentation for information about what features it
/// requires.
///
/// ## Using `Requester` in a generic context
///
/// When writing helper function you may be indifferent to which exact type is
/// being used as a bot and instead only care that it implements `Requester`
/// trait. In this case you can use generic bounds to express this exact thing:
///
/// ```
/// use teloxide_core::{
///     prelude::*,
///     types::{ChatId, Message},
/// };
///
/// async fn send_hi<R>(bot: R, chat: ChatId) -> Message
/// where
///     R: Requester,
/// {
///     bot.send_message(chat, "hi").await.expect("error")
/// }
///
/// // `send_hi` can be called with `Bot`, `DefaultParseMode<Bot>` and so on, and so forth
/// ```
///
/// [`Bot`]: crate::Bot
/// [`FlatMap`]: std::iter::FlatMap
/// [`Filter`]: std::iter::Filter
/// [`adaptors`]: crate::adaptors
/// [`DefaultParseMode`]: crate::adaptors::DefaultParseMode
/// [`Throttle`]: crate::adaptors::Throttle
/// [`RequesterExt`]: crate::requests::RequesterExt
/// [`.parse_mode(...)`]: crate::requests::RequesterExt::parse_mode
#[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))]
pub trait Requester {
    /// Error type returned by all requests.
    type Err: std::error::Error + Send + AsResponseParameters;

    // START BLOCK requester_methods
    // Generated by `codegen_requester_methods`, do not edit by hand.

    type GetUpdates: Request<Payload = GetUpdates, Err = Self::Err>;

    /// For Telegram documentation see [`GetUpdates`].
    fn get_updates(&self) -> Self::GetUpdates;

    type SetWebhook: Request<Payload = SetWebhook, Err = Self::Err>;

    /// For Telegram documentation see [`SetWebhook`].
    fn set_webhook(&self, url: Url) -> Self::SetWebhook;

    type DeleteWebhook: Request<Payload = DeleteWebhook, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteWebhook`].
    fn delete_webhook(&self) -> Self::DeleteWebhook;

    type GetWebhookInfo: Request<Payload = GetWebhookInfo, Err = Self::Err>;

    /// For Telegram documentation see [`GetWebhookInfo`].
    fn get_webhook_info(&self) -> Self::GetWebhookInfo;

    type GetMe: Request<Payload = GetMe, Err = Self::Err>;

    /// For Telegram documentation see [`GetMe`].
    fn get_me(&self) -> Self::GetMe;

    type LogOut: Request<Payload = LogOut, Err = Self::Err>;

    /// For Telegram documentation see [`LogOut`].
    fn log_out(&self) -> Self::LogOut;

    type Close: Request<Payload = Close, Err = Self::Err>;

    /// For Telegram documentation see [`Close`].
    fn close(&self) -> Self::Close;

    type SendMessage: Request<Payload = SendMessage, Err = Self::Err>;

    /// For Telegram documentation see [`SendMessage`].
    fn send_message<C, T>(&self, chat_id: C, text: T) -> Self::SendMessage
    where
        C: Into<Recipient>,
        T: Into<String>;

    type ForwardMessage: Request<Payload = ForwardMessage, Err = Self::Err>;

    /// For Telegram documentation see [`ForwardMessage`].
    fn forward_message<C, F>(
        &self,
        chat_id: C,
        from_chat_id: F,
        message_id: MessageId,
    ) -> Self::ForwardMessage
    where
        C: Into<Recipient>,
        F: Into<Recipient>;

    type ForwardMessages: Request<Payload = ForwardMessages, Err = Self::Err>;

    /// For Telegram documentation see [`ForwardMessages`].
    fn forward_messages<C, F, M>(
        &self,
        chat_id: C,
        from_chat_id: F,
        message_ids: M,
    ) -> Self::ForwardMessages
    where
        C: Into<Recipient>,
        F: Into<Recipient>,
        M: IntoIterator<Item = MessageId>;

    type CopyMessage: Request<Payload = CopyMessage, Err = Self::Err>;

    /// For Telegram documentation see [`CopyMessage`].
    fn copy_message<C, F>(
        &self,
        chat_id: C,
        from_chat_id: F,
        message_id: MessageId,
    ) -> Self::CopyMessage
    where
        C: Into<Recipient>,
        F: Into<Recipient>;

    type CopyMessages: Request<Payload = CopyMessages, Err = Self::Err>;

    /// For Telegram documentation see [`CopyMessages`].
    fn copy_messages<C, F, M>(
        &self,
        chat_id: C,
        from_chat_id: F,
        message_ids: M,
    ) -> Self::CopyMessages
    where
        C: Into<Recipient>,
        F: Into<Recipient>,
        M: IntoIterator<Item = MessageId>;

    type SendPhoto: Request<Payload = SendPhoto, Err = Self::Err>;

    /// For Telegram documentation see [`SendPhoto`].
    fn send_photo<C>(&self, chat_id: C, photo: InputFile) -> Self::SendPhoto
    where
        C: Into<Recipient>;

    type SendAudio: Request<Payload = SendAudio, Err = Self::Err>;

    /// For Telegram documentation see [`SendAudio`].
    fn send_audio<C>(&self, chat_id: C, audio: InputFile) -> Self::SendAudio
    where
        C: Into<Recipient>;

    type SendDocument: Request<Payload = SendDocument, Err = Self::Err>;

    /// For Telegram documentation see [`SendDocument`].
    fn send_document<C>(&self, chat_id: C, document: InputFile) -> Self::SendDocument
    where
        C: Into<Recipient>;

    type SendVideo: Request<Payload = SendVideo, Err = Self::Err>;

    /// For Telegram documentation see [`SendVideo`].
    fn send_video<C>(&self, chat_id: C, video: InputFile) -> Self::SendVideo
    where
        C: Into<Recipient>;

    type SendAnimation: Request<Payload = SendAnimation, Err = Self::Err>;

    /// For Telegram documentation see [`SendAnimation`].
    fn send_animation<C>(&self, chat_id: C, animation: InputFile) -> Self::SendAnimation
    where
        C: Into<Recipient>;

    type SendVoice: Request<Payload = SendVoice, Err = Self::Err>;

    /// For Telegram documentation see [`SendVoice`].
    fn send_voice<C>(&self, chat_id: C, voice: InputFile) -> Self::SendVoice
    where
        C: Into<Recipient>;

    type SendVideoNote: Request<Payload = SendVideoNote, Err = Self::Err>;

    /// For Telegram documentation see [`SendVideoNote`].
    fn send_video_note<C>(&self, chat_id: C, video_note: InputFile) -> Self::SendVideoNote
    where
        C: Into<Recipient>;

    type SendPaidMedia: Request<Payload = SendPaidMedia, Err = Self::Err>;

    /// For Telegram documentation see [`SendPaidMedia`].
    fn send_paid_media<C, M>(&self, chat_id: C, star_count: u32, media: M) -> Self::SendPaidMedia
    where
        C: Into<Recipient>,
        M: IntoIterator<Item = InputPaidMedia>;

    type SendMediaGroup: Request<Payload = SendMediaGroup, Err = Self::Err>;

    /// For Telegram documentation see [`SendMediaGroup`].
    fn send_media_group<C, M>(&self, chat_id: C, media: M) -> Self::SendMediaGroup
    where
        C: Into<Recipient>,
        M: IntoIterator<Item = InputMedia>;

    type SendLocation: Request<Payload = SendLocation, Err = Self::Err>;

    /// For Telegram documentation see [`SendLocation`].
    fn send_location<C>(&self, chat_id: C, latitude: f64, longitude: f64) -> Self::SendLocation
    where
        C: Into<Recipient>;

    type EditMessageLiveLocation: Request<Payload = EditMessageLiveLocation, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageLiveLocation`].
    fn edit_message_live_location<C>(
        &self,
        chat_id: C,
        message_id: MessageId,
        latitude: f64,
        longitude: f64,
    ) -> Self::EditMessageLiveLocation
    where
        C: Into<Recipient>;

    type EditMessageLiveLocationInline: Request<
        Payload = EditMessageLiveLocationInline,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`EditMessageLiveLocationInline`].
    fn edit_message_live_location_inline<I>(
        &self,
        inline_message_id: I,
        latitude: f64,
        longitude: f64,
    ) -> Self::EditMessageLiveLocationInline
    where
        I: Into<String>;

    type StopMessageLiveLocation: Request<Payload = StopMessageLiveLocation, Err = Self::Err>;

    /// For Telegram documentation see [`StopMessageLiveLocation`].
    fn stop_message_live_location<C>(
        &self,
        chat_id: C,
        message_id: MessageId,
    ) -> Self::StopMessageLiveLocation
    where
        C: Into<Recipient>;

    type StopMessageLiveLocationInline: Request<
        Payload = StopMessageLiveLocationInline,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`StopMessageLiveLocationInline`].
    fn stop_message_live_location_inline<I>(
        &self,
        inline_message_id: I,
    ) -> Self::StopMessageLiveLocationInline
    where
        I: Into<String>;

    type EditMessageChecklist: Request<Payload = EditMessageChecklist, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageChecklist`].
    fn edit_message_checklist<C>(
        &self,
        business_connection_id: BusinessConnectionId,
        chat_id: C,
        message_id: MessageId,
        checklist: InputChecklist,
    ) -> Self::EditMessageChecklist
    where
        C: Into<ChatId>;

    type SendVenue: Request<Payload = SendVenue, Err = Self::Err>;

    /// For Telegram documentation see [`SendVenue`].
    fn send_venue<C, T, A>(
        &self,
        chat_id: C,
        latitude: f64,
        longitude: f64,
        title: T,
        address: A,
    ) -> Self::SendVenue
    where
        C: Into<Recipient>,
        T: Into<String>,
        A: Into<String>;

    type SendContact: Request<Payload = SendContact, Err = Self::Err>;

    /// For Telegram documentation see [`SendContact`].
    fn send_contact<C, P, F>(
        &self,
        chat_id: C,
        phone_number: P,
        first_name: F,
    ) -> Self::SendContact
    where
        C: Into<Recipient>,
        P: Into<String>,
        F: Into<String>;

    type SendPoll: Request<Payload = SendPoll, Err = Self::Err>;

    /// For Telegram documentation see [`SendPoll`].
    fn send_poll<C, Q, O>(&self, chat_id: C, question: Q, options: O) -> Self::SendPoll
    where
        C: Into<Recipient>,
        Q: Into<String>,
        O: IntoIterator<Item = InputPollOption>;

    type SendChecklist: Request<Payload = SendChecklist, Err = Self::Err>;

    /// For Telegram documentation see [`SendChecklist`].
    fn send_checklist<C>(
        &self,
        business_connection_id: BusinessConnectionId,
        chat_id: C,
        checklist: InputChecklist,
    ) -> Self::SendChecklist
    where
        C: Into<ChatId>;

    type SendDice: Request<Payload = SendDice, Err = Self::Err>;

    /// For Telegram documentation see [`SendDice`].
    fn send_dice<C>(&self, chat_id: C) -> Self::SendDice
    where
        C: Into<Recipient>;

    type SendChatAction: Request<Payload = SendChatAction, Err = Self::Err>;

    /// For Telegram documentation see [`SendChatAction`].
    fn send_chat_action<C>(&self, chat_id: C, action: ChatAction) -> Self::SendChatAction
    where
        C: Into<Recipient>;

    type SetMessageReaction: Request<Payload = SetMessageReaction, Err = Self::Err>;

    /// For Telegram documentation see [`SetMessageReaction`].
    fn set_message_reaction<C>(
        &self,
        chat_id: C,
        message_id: MessageId,
    ) -> Self::SetMessageReaction
    where
        C: Into<Recipient>;

    type GetUserProfilePhotos: Request<Payload = GetUserProfilePhotos, Err = Self::Err>;

    /// For Telegram documentation see [`GetUserProfilePhotos`].
    fn get_user_profile_photos(&self, user_id: UserId) -> Self::GetUserProfilePhotos;

    type SetUserEmojiStatus: Request<Payload = SetUserEmojiStatus, Err = Self::Err>;

    /// For Telegram documentation see [`SetUserEmojiStatus`].
    fn set_user_emoji_status(&self, user_id: UserId) -> Self::SetUserEmojiStatus;

    type GetFile: Request<Payload = GetFile, Err = Self::Err>;

    /// For Telegram documentation see [`GetFile`].
    fn get_file(&self, file_id: FileId) -> Self::GetFile;

    type BanChatMember: Request<Payload = BanChatMember, Err = Self::Err>;

    /// For Telegram documentation see [`BanChatMember`].
    fn ban_chat_member<C>(&self, chat_id: C, user_id: UserId) -> Self::BanChatMember
    where
        C: Into<Recipient>;

    type KickChatMember: Request<Payload = KickChatMember, Err = Self::Err>;

    /// For Telegram documentation see [`KickChatMember`].
    fn kick_chat_member<C>(&self, chat_id: C, user_id: UserId) -> Self::KickChatMember
    where
        C: Into<Recipient>;

    type UnbanChatMember: Request<Payload = UnbanChatMember, Err = Self::Err>;

    /// For Telegram documentation see [`UnbanChatMember`].
    fn unban_chat_member<C>(&self, chat_id: C, user_id: UserId) -> Self::UnbanChatMember
    where
        C: Into<Recipient>;

    type RestrictChatMember: Request<Payload = RestrictChatMember, Err = Self::Err>;

    /// For Telegram documentation see [`RestrictChatMember`].
    fn restrict_chat_member<C>(
        &self,
        chat_id: C,
        user_id: UserId,
        permissions: ChatPermissions,
    ) -> Self::RestrictChatMember
    where
        C: Into<Recipient>;

    type PromoteChatMember: Request<Payload = PromoteChatMember, Err = Self::Err>;

    /// For Telegram documentation see [`PromoteChatMember`].
    fn promote_chat_member<C>(&self, chat_id: C, user_id: UserId) -> Self::PromoteChatMember
    where
        C: Into<Recipient>;

    type SetChatAdministratorCustomTitle: Request<
        Payload = SetChatAdministratorCustomTitle,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`SetChatAdministratorCustomTitle`].
    fn set_chat_administrator_custom_title<Ch, C>(
        &self,
        chat_id: Ch,
        user_id: UserId,
        custom_title: C,
    ) -> Self::SetChatAdministratorCustomTitle
    where
        Ch: Into<Recipient>,
        C: Into<String>;

    type BanChatSenderChat: Request<Payload = BanChatSenderChat, Err = Self::Err>;

    /// For Telegram documentation see [`BanChatSenderChat`].
    fn ban_chat_sender_chat<C, S>(&self, chat_id: C, sender_chat_id: S) -> Self::BanChatSenderChat
    where
        C: Into<Recipient>,
        S: Into<ChatId>;

    type UnbanChatSenderChat: Request<Payload = UnbanChatSenderChat, Err = Self::Err>;

    /// For Telegram documentation see [`UnbanChatSenderChat`].
    fn unban_chat_sender_chat<C, S>(
        &self,
        chat_id: C,
        sender_chat_id: S,
    ) -> Self::UnbanChatSenderChat
    where
        C: Into<Recipient>,
        S: Into<ChatId>;

    type SetChatPermissions: Request<Payload = SetChatPermissions, Err = Self::Err>;

    /// For Telegram documentation see [`SetChatPermissions`].
    fn set_chat_permissions<C>(
        &self,
        chat_id: C,
        permissions: ChatPermissions,
    ) -> Self::SetChatPermissions
    where
        C: Into<Recipient>;

    type ExportChatInviteLink: Request<Payload = ExportChatInviteLink, Err = Self::Err>;

    /// For Telegram documentation see [`ExportChatInviteLink`].
    fn export_chat_invite_link<C>(&self, chat_id: C) -> Self::ExportChatInviteLink
    where
        C: Into<Recipient>;

    type CreateChatInviteLink: Request<Payload = CreateChatInviteLink, Err = Self::Err>;

    /// For Telegram documentation see [`CreateChatInviteLink`].
    fn create_chat_invite_link<C>(&self, chat_id: C) -> Self::CreateChatInviteLink
    where
        C: Into<Recipient>;

    type EditChatInviteLink: Request<Payload = EditChatInviteLink, Err = Self::Err>;

    /// For Telegram documentation see [`EditChatInviteLink`].
    fn edit_chat_invite_link<C, I>(&self, chat_id: C, invite_link: I) -> Self::EditChatInviteLink
    where
        C: Into<Recipient>,
        I: Into<String>;

    type CreateChatSubscriptionInviteLink: Request<
        Payload = CreateChatSubscriptionInviteLink,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`CreateChatSubscriptionInviteLink`].
    fn create_chat_subscription_invite_link<C>(
        &self,
        chat_id: C,
        subscription_period: Seconds,
        subscription_price: u32,
    ) -> Self::CreateChatSubscriptionInviteLink
    where
        C: Into<Recipient>;

    type EditChatSubscriptionInviteLink: Request<
        Payload = EditChatSubscriptionInviteLink,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`EditChatSubscriptionInviteLink`].
    fn edit_chat_subscription_invite_link<C, I>(
        &self,
        chat_id: C,
        invite_link: I,
    ) -> Self::EditChatSubscriptionInviteLink
    where
        C: Into<Recipient>,
        I: Into<String>;

    type RevokeChatInviteLink: Request<Payload = RevokeChatInviteLink, Err = Self::Err>;

    /// For Telegram documentation see [`RevokeChatInviteLink`].
    fn revoke_chat_invite_link<C, I>(
        &self,
        chat_id: C,
        invite_link: I,
    ) -> Self::RevokeChatInviteLink
    where
        C: Into<Recipient>,
        I: Into<String>;

    type ApproveChatJoinRequest: Request<Payload = ApproveChatJoinRequest, Err = Self::Err>;

    /// For Telegram documentation see [`ApproveChatJoinRequest`].
    fn approve_chat_join_request<C>(
        &self,
        chat_id: C,
        user_id: UserId,
    ) -> Self::ApproveChatJoinRequest
    where
        C: Into<Recipient>;

    type DeclineChatJoinRequest: Request<Payload = DeclineChatJoinRequest, Err = Self::Err>;

    /// For Telegram documentation see [`DeclineChatJoinRequest`].
    fn decline_chat_join_request<C>(
        &self,
        chat_id: C,
        user_id: UserId,
    ) -> Self::DeclineChatJoinRequest
    where
        C: Into<Recipient>;

    type SetChatPhoto: Request<Payload = SetChatPhoto, Err = Self::Err>;

    /// For Telegram documentation see [`SetChatPhoto`].
    fn set_chat_photo<C>(&self, chat_id: C, photo: InputFile) -> Self::SetChatPhoto
    where
        C: Into<Recipient>;

    type DeleteChatPhoto: Request<Payload = DeleteChatPhoto, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteChatPhoto`].
    fn delete_chat_photo<C>(&self, chat_id: C) -> Self::DeleteChatPhoto
    where
        C: Into<Recipient>;

    type SetChatTitle: Request<Payload = SetChatTitle, Err = Self::Err>;

    /// For Telegram documentation see [`SetChatTitle`].
    fn set_chat_title<C, T>(&self, chat_id: C, title: T) -> Self::SetChatTitle
    where
        C: Into<Recipient>,
        T: Into<String>;

    type SetChatDescription: Request<Payload = SetChatDescription, Err = Self::Err>;

    /// For Telegram documentation see [`SetChatDescription`].
    fn set_chat_description<C>(&self, chat_id: C) -> Self::SetChatDescription
    where
        C: Into<Recipient>;

    type PinChatMessage: Request<Payload = PinChatMessage, Err = Self::Err>;

    /// For Telegram documentation see [`PinChatMessage`].
    fn pin_chat_message<C>(&self, chat_id: C, message_id: MessageId) -> Self::PinChatMessage
    where
        C: Into<Recipient>;

    type UnpinChatMessage: Request<Payload = UnpinChatMessage, Err = Self::Err>;

    /// For Telegram documentation see [`UnpinChatMessage`].
    fn unpin_chat_message<C>(&self, chat_id: C) -> Self::UnpinChatMessage
    where
        C: Into<Recipient>;

    type UnpinAllChatMessages: Request<Payload = UnpinAllChatMessages, Err = Self::Err>;

    /// For Telegram documentation see [`UnpinAllChatMessages`].
    fn unpin_all_chat_messages<C>(&self, chat_id: C) -> Self::UnpinAllChatMessages
    where
        C: Into<Recipient>;

    type LeaveChat: Request<Payload = LeaveChat, Err = Self::Err>;

    /// For Telegram documentation see [`LeaveChat`].
    fn leave_chat<C>(&self, chat_id: C) -> Self::LeaveChat
    where
        C: Into<Recipient>;

    type GetChat: Request<Payload = GetChat, Err = Self::Err>;

    /// For Telegram documentation see [`GetChat`].
    fn get_chat<C>(&self, chat_id: C) -> Self::GetChat
    where
        C: Into<Recipient>;

    type GetChatAdministrators: Request<Payload = GetChatAdministrators, Err = Self::Err>;

    /// For Telegram documentation see [`GetChatAdministrators`].
    fn get_chat_administrators<C>(&self, chat_id: C) -> Self::GetChatAdministrators
    where
        C: Into<Recipient>;

    type GetChatMemberCount: Request<Payload = GetChatMemberCount, Err = Self::Err>;

    /// For Telegram documentation see [`GetChatMemberCount`].
    fn get_chat_member_count<C>(&self, chat_id: C) -> Self::GetChatMemberCount
    where
        C: Into<Recipient>;

    type GetChatMembersCount: Request<Payload = GetChatMembersCount, Err = Self::Err>;

    /// For Telegram documentation see [`GetChatMembersCount`].
    fn get_chat_members_count<C>(&self, chat_id: C) -> Self::GetChatMembersCount
    where
        C: Into<Recipient>;

    type GetChatMember: Request<Payload = GetChatMember, Err = Self::Err>;

    /// For Telegram documentation see [`GetChatMember`].
    fn get_chat_member<C>(&self, chat_id: C, user_id: UserId) -> Self::GetChatMember
    where
        C: Into<Recipient>;

    type SetChatStickerSet: Request<Payload = SetChatStickerSet, Err = Self::Err>;

    /// For Telegram documentation see [`SetChatStickerSet`].
    fn set_chat_sticker_set<C, S>(
        &self,
        chat_id: C,
        sticker_set_name: S,
    ) -> Self::SetChatStickerSet
    where
        C: Into<Recipient>,
        S: Into<String>;

    type DeleteChatStickerSet: Request<Payload = DeleteChatStickerSet, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteChatStickerSet`].
    fn delete_chat_sticker_set<C>(&self, chat_id: C) -> Self::DeleteChatStickerSet
    where
        C: Into<Recipient>;

    type GetForumTopicIconStickers: Request<Payload = GetForumTopicIconStickers, Err = Self::Err>;

    /// For Telegram documentation see [`GetForumTopicIconStickers`].
    fn get_forum_topic_icon_stickers(&self) -> Self::GetForumTopicIconStickers;

    type CreateForumTopic: Request<Payload = CreateForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`CreateForumTopic`].
    fn create_forum_topic<C, N>(&self, chat_id: C, name: N) -> Self::CreateForumTopic
    where
        C: Into<Recipient>,
        N: Into<String>;

    type EditForumTopic: Request<Payload = EditForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`EditForumTopic`].
    fn edit_forum_topic<C>(&self, chat_id: C, message_thread_id: ThreadId) -> Self::EditForumTopic
    where
        C: Into<Recipient>;

    type CloseForumTopic: Request<Payload = CloseForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`CloseForumTopic`].
    fn close_forum_topic<C>(
        &self,
        chat_id: C,
        message_thread_id: ThreadId,
    ) -> Self::CloseForumTopic
    where
        C: Into<Recipient>;

    type ReopenForumTopic: Request<Payload = ReopenForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`ReopenForumTopic`].
    fn reopen_forum_topic<C>(
        &self,
        chat_id: C,
        message_thread_id: ThreadId,
    ) -> Self::ReopenForumTopic
    where
        C: Into<Recipient>;

    type DeleteForumTopic: Request<Payload = DeleteForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteForumTopic`].
    fn delete_forum_topic<C>(
        &self,
        chat_id: C,
        message_thread_id: ThreadId,
    ) -> Self::DeleteForumTopic
    where
        C: Into<Recipient>;

    type UnpinAllForumTopicMessages: Request<Payload = UnpinAllForumTopicMessages, Err = Self::Err>;

    /// For Telegram documentation see [`UnpinAllForumTopicMessages`].
    fn unpin_all_forum_topic_messages<C>(
        &self,
        chat_id: C,
        message_thread_id: ThreadId,
    ) -> Self::UnpinAllForumTopicMessages
    where
        C: Into<Recipient>;

    type EditGeneralForumTopic: Request<Payload = EditGeneralForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`EditGeneralForumTopic`].
    fn edit_general_forum_topic<C, N>(&self, chat_id: C, name: N) -> Self::EditGeneralForumTopic
    where
        C: Into<Recipient>,
        N: Into<String>;

    type CloseGeneralForumTopic: Request<Payload = CloseGeneralForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`CloseGeneralForumTopic`].
    fn close_general_forum_topic<C>(&self, chat_id: C) -> Self::CloseGeneralForumTopic
    where
        C: Into<Recipient>;

    type ReopenGeneralForumTopic: Request<Payload = ReopenGeneralForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`ReopenGeneralForumTopic`].
    fn reopen_general_forum_topic<C>(&self, chat_id: C) -> Self::ReopenGeneralForumTopic
    where
        C: Into<Recipient>;

    type HideGeneralForumTopic: Request<Payload = HideGeneralForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`HideGeneralForumTopic`].
    fn hide_general_forum_topic<C>(&self, chat_id: C) -> Self::HideGeneralForumTopic
    where
        C: Into<Recipient>;

    type UnhideGeneralForumTopic: Request<Payload = UnhideGeneralForumTopic, Err = Self::Err>;

    /// For Telegram documentation see [`UnhideGeneralForumTopic`].
    fn unhide_general_forum_topic<C>(&self, chat_id: C) -> Self::UnhideGeneralForumTopic
    where
        C: Into<Recipient>;

    type UnpinAllGeneralForumTopicMessages: Request<
        Payload = UnpinAllGeneralForumTopicMessages,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`UnpinAllGeneralForumTopicMessages`].
    fn unpin_all_general_forum_topic_messages<C>(
        &self,
        chat_id: C,
    ) -> Self::UnpinAllGeneralForumTopicMessages
    where
        C: Into<Recipient>;

    type AnswerCallbackQuery: Request<Payload = AnswerCallbackQuery, Err = Self::Err>;

    /// For Telegram documentation see [`AnswerCallbackQuery`].
    fn answer_callback_query(
        &self,
        callback_query_id: CallbackQueryId,
    ) -> Self::AnswerCallbackQuery;

    type GetUserChatBoosts: Request<Payload = GetUserChatBoosts, Err = Self::Err>;

    /// For Telegram documentation see [`GetUserChatBoosts`].
    fn get_user_chat_boosts<C>(&self, chat_id: C, user_id: UserId) -> Self::GetUserChatBoosts
    where
        C: Into<Recipient>;

    type SetMyCommands: Request<Payload = SetMyCommands, Err = Self::Err>;

    /// For Telegram documentation see [`SetMyCommands`].
    fn set_my_commands<C>(&self, commands: C) -> Self::SetMyCommands
    where
        C: IntoIterator<Item = BotCommand>;

    type GetBusinessConnection: Request<Payload = GetBusinessConnection, Err = Self::Err>;

    /// For Telegram documentation see [`GetBusinessConnection`].
    fn get_business_connection(
        &self,
        business_connection_id: BusinessConnectionId,
    ) -> Self::GetBusinessConnection;

    type GetMyCommands: Request<Payload = GetMyCommands, Err = Self::Err>;

    /// For Telegram documentation see [`GetMyCommands`].
    fn get_my_commands(&self) -> Self::GetMyCommands;

    type SetMyName: Request<Payload = SetMyName, Err = Self::Err>;

    /// For Telegram documentation see [`SetMyName`].
    fn set_my_name(&self) -> Self::SetMyName;

    type GetMyName: Request<Payload = GetMyName, Err = Self::Err>;

    /// For Telegram documentation see [`GetMyName`].
    fn get_my_name(&self) -> Self::GetMyName;

    type SetMyDescription: Request<Payload = SetMyDescription, Err = Self::Err>;

    /// For Telegram documentation see [`SetMyDescription`].
    fn set_my_description(&self) -> Self::SetMyDescription;

    type GetMyDescription: Request<Payload = GetMyDescription, Err = Self::Err>;

    /// For Telegram documentation see [`GetMyDescription`].
    fn get_my_description(&self) -> Self::GetMyDescription;

    type SetMyShortDescription: Request<Payload = SetMyShortDescription, Err = Self::Err>;

    /// For Telegram documentation see [`SetMyShortDescription`].
    fn set_my_short_description(&self) -> Self::SetMyShortDescription;

    type GetMyShortDescription: Request<Payload = GetMyShortDescription, Err = Self::Err>;

    /// For Telegram documentation see [`GetMyShortDescription`].
    fn get_my_short_description(&self) -> Self::GetMyShortDescription;

    type SetChatMenuButton: Request<Payload = SetChatMenuButton, Err = Self::Err>;

    /// For Telegram documentation see [`SetChatMenuButton`].
    fn set_chat_menu_button(&self) -> Self::SetChatMenuButton;

    type GetChatMenuButton: Request<Payload = GetChatMenuButton, Err = Self::Err>;

    /// For Telegram documentation see [`GetChatMenuButton`].
    fn get_chat_menu_button(&self) -> Self::GetChatMenuButton;

    type SetMyDefaultAdministratorRights: Request<
        Payload = SetMyDefaultAdministratorRights,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`SetMyDefaultAdministratorRights`].
    fn set_my_default_administrator_rights(&self) -> Self::SetMyDefaultAdministratorRights;

    type GetMyDefaultAdministratorRights: Request<
        Payload = GetMyDefaultAdministratorRights,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`GetMyDefaultAdministratorRights`].
    fn get_my_default_administrator_rights(&self) -> Self::GetMyDefaultAdministratorRights;

    type DeleteMyCommands: Request<Payload = DeleteMyCommands, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteMyCommands`].
    fn delete_my_commands(&self) -> Self::DeleteMyCommands;

    type AnswerInlineQuery: Request<Payload = AnswerInlineQuery, Err = Self::Err>;

    /// For Telegram documentation see [`AnswerInlineQuery`].
    fn answer_inline_query<R>(
        &self,
        inline_query_id: InlineQueryId,
        results: R,
    ) -> Self::AnswerInlineQuery
    where
        R: IntoIterator<Item = InlineQueryResult>;

    type AnswerWebAppQuery: Request<Payload = AnswerWebAppQuery, Err = Self::Err>;

    /// For Telegram documentation see [`AnswerWebAppQuery`].
    fn answer_web_app_query<W>(
        &self,
        web_app_query_id: W,
        result: InlineQueryResult,
    ) -> Self::AnswerWebAppQuery
    where
        W: Into<String>;

    type SavePreparedInlineMessage: Request<Payload = SavePreparedInlineMessage, Err = Self::Err>;

    /// For Telegram documentation see [`SavePreparedInlineMessage`].
    fn save_prepared_inline_message(
        &self,
        user_id: UserId,
        result: InlineQueryResult,
    ) -> Self::SavePreparedInlineMessage;

    type EditMessageText: Request<Payload = EditMessageText, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageText`].
    fn edit_message_text<C, T>(
        &self,
        chat_id: C,
        message_id: MessageId,
        text: T,
    ) -> Self::EditMessageText
    where
        C: Into<Recipient>,
        T: Into<String>;

    type EditMessageTextInline: Request<Payload = EditMessageTextInline, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageTextInline`].
    fn edit_message_text_inline<I, T>(
        &self,
        inline_message_id: I,
        text: T,
    ) -> Self::EditMessageTextInline
    where
        I: Into<String>,
        T: Into<String>;

    type EditMessageCaption: Request<Payload = EditMessageCaption, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageCaption`].
    fn edit_message_caption<C>(
        &self,
        chat_id: C,
        message_id: MessageId,
    ) -> Self::EditMessageCaption
    where
        C: Into<Recipient>;

    type EditMessageCaptionInline: Request<Payload = EditMessageCaptionInline, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageCaptionInline`].
    fn edit_message_caption_inline<I>(
        &self,
        inline_message_id: I,
    ) -> Self::EditMessageCaptionInline
    where
        I: Into<String>;

    type EditMessageMedia: Request<Payload = EditMessageMedia, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageMedia`].
    fn edit_message_media<C>(
        &self,
        chat_id: C,
        message_id: MessageId,
        media: InputMedia,
    ) -> Self::EditMessageMedia
    where
        C: Into<Recipient>;

    type EditMessageMediaInline: Request<Payload = EditMessageMediaInline, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageMediaInline`].
    fn edit_message_media_inline<I>(
        &self,
        inline_message_id: I,
        media: InputMedia,
    ) -> Self::EditMessageMediaInline
    where
        I: Into<String>;

    type EditMessageReplyMarkup: Request<Payload = EditMessageReplyMarkup, Err = Self::Err>;

    /// For Telegram documentation see [`EditMessageReplyMarkup`].
    fn edit_message_reply_markup<C>(
        &self,
        chat_id: C,
        message_id: MessageId,
    ) -> Self::EditMessageReplyMarkup
    where
        C: Into<Recipient>;

    type EditMessageReplyMarkupInline: Request<
        Payload = EditMessageReplyMarkupInline,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`EditMessageReplyMarkupInline`].
    fn edit_message_reply_markup_inline<I>(
        &self,
        inline_message_id: I,
    ) -> Self::EditMessageReplyMarkupInline
    where
        I: Into<String>;

    type StopPoll: Request<Payload = StopPoll, Err = Self::Err>;

    /// For Telegram documentation see [`StopPoll`].
    fn stop_poll<C>(&self, chat_id: C, message_id: MessageId) -> Self::StopPoll
    where
        C: Into<Recipient>;

    type DeleteMessage: Request<Payload = DeleteMessage, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteMessage`].
    fn delete_message<C>(&self, chat_id: C, message_id: MessageId) -> Self::DeleteMessage
    where
        C: Into<Recipient>;

    type DeleteMessages: Request<Payload = DeleteMessages, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteMessages`].
    fn delete_messages<C, M>(&self, chat_id: C, message_ids: M) -> Self::DeleteMessages
    where
        C: Into<Recipient>,
        M: IntoIterator<Item = MessageId>;

    type SendSticker: Request<Payload = SendSticker, Err = Self::Err>;

    /// For Telegram documentation see [`SendSticker`].
    fn send_sticker<C>(&self, chat_id: C, sticker: InputFile) -> Self::SendSticker
    where
        C: Into<Recipient>;

    type GetStickerSet: Request<Payload = GetStickerSet, Err = Self::Err>;

    /// For Telegram documentation see [`GetStickerSet`].
    fn get_sticker_set<N>(&self, name: N) -> Self::GetStickerSet
    where
        N: Into<String>;

    type GetCustomEmojiStickers: Request<Payload = GetCustomEmojiStickers, Err = Self::Err>;

    /// For Telegram documentation see [`GetCustomEmojiStickers`].
    fn get_custom_emoji_stickers<C>(&self, custom_emoji_ids: C) -> Self::GetCustomEmojiStickers
    where
        C: IntoIterator<Item = CustomEmojiId>;

    type UploadStickerFile: Request<Payload = UploadStickerFile, Err = Self::Err>;

    /// For Telegram documentation see [`UploadStickerFile`].
    fn upload_sticker_file(
        &self,
        user_id: UserId,
        sticker: InputFile,
        sticker_format: StickerFormat,
    ) -> Self::UploadStickerFile;

    type CreateNewStickerSet: Request<Payload = CreateNewStickerSet, Err = Self::Err>;

    /// For Telegram documentation see [`CreateNewStickerSet`].
    fn create_new_sticker_set<N, T, S>(
        &self,
        user_id: UserId,
        name: N,
        title: T,
        stickers: S,
    ) -> Self::CreateNewStickerSet
    where
        N: Into<String>,
        T: Into<String>,
        S: IntoIterator<Item = InputSticker>;

    type AddStickerToSet: Request<Payload = AddStickerToSet, Err = Self::Err>;

    /// For Telegram documentation see [`AddStickerToSet`].
    fn add_sticker_to_set<N>(
        &self,
        user_id: UserId,
        name: N,
        sticker: InputSticker,
    ) -> Self::AddStickerToSet
    where
        N: Into<String>;

    type SetStickerPositionInSet: Request<Payload = SetStickerPositionInSet, Err = Self::Err>;

    /// For Telegram documentation see [`SetStickerPositionInSet`].
    fn set_sticker_position_in_set<S>(
        &self,
        sticker: S,
        position: u32,
    ) -> Self::SetStickerPositionInSet
    where
        S: Into<String>;

    type DeleteStickerFromSet: Request<Payload = DeleteStickerFromSet, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteStickerFromSet`].
    fn delete_sticker_from_set<S>(&self, sticker: S) -> Self::DeleteStickerFromSet
    where
        S: Into<String>;

    type ReplaceStickerInSet: Request<Payload = ReplaceStickerInSet, Err = Self::Err>;

    /// For Telegram documentation see [`ReplaceStickerInSet`].
    fn replace_sticker_in_set<N, O>(
        &self,
        user_id: UserId,
        name: N,
        old_sticker: O,
        sticker: InputSticker,
    ) -> Self::ReplaceStickerInSet
    where
        N: Into<String>,
        O: Into<String>;

    type SetStickerSetThumbnail: Request<Payload = SetStickerSetThumbnail, Err = Self::Err>;

    /// For Telegram documentation see [`SetStickerSetThumbnail`].
    fn set_sticker_set_thumbnail<N>(
        &self,
        name: N,
        user_id: UserId,
        format: StickerFormat,
    ) -> Self::SetStickerSetThumbnail
    where
        N: Into<String>;

    type SetCustomEmojiStickerSetThumbnail: Request<
        Payload = SetCustomEmojiStickerSetThumbnail,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`SetCustomEmojiStickerSetThumbnail`].
    fn set_custom_emoji_sticker_set_thumbnail<N>(
        &self,
        name: N,
    ) -> Self::SetCustomEmojiStickerSetThumbnail
    where
        N: Into<String>;

    type SetStickerSetTitle: Request<Payload = SetStickerSetTitle, Err = Self::Err>;

    /// For Telegram documentation see [`SetStickerSetTitle`].
    fn set_sticker_set_title<N, T>(&self, name: N, title: T) -> Self::SetStickerSetTitle
    where
        N: Into<String>,
        T: Into<String>;

    type DeleteStickerSet: Request<Payload = DeleteStickerSet, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteStickerSet`].
    fn delete_sticker_set<N>(&self, name: N) -> Self::DeleteStickerSet
    where
        N: Into<String>;

    type SetStickerEmojiList: Request<Payload = SetStickerEmojiList, Err = Self::Err>;

    /// For Telegram documentation see [`SetStickerEmojiList`].
    fn set_sticker_emoji_list<S, E>(&self, sticker: S, emoji_list: E) -> Self::SetStickerEmojiList
    where
        S: Into<String>,
        E: IntoIterator<Item = String>;

    type SetStickerKeywords: Request<Payload = SetStickerKeywords, Err = Self::Err>;

    /// For Telegram documentation see [`SetStickerKeywords`].
    fn set_sticker_keywords<S>(&self, sticker: S) -> Self::SetStickerKeywords
    where
        S: Into<String>;

    type SetStickerMaskPosition: Request<Payload = SetStickerMaskPosition, Err = Self::Err>;

    /// For Telegram documentation see [`SetStickerMaskPosition`].
    fn set_sticker_mask_position<S>(&self, sticker: S) -> Self::SetStickerMaskPosition
    where
        S: Into<String>;

    type GetAvailableGifts: Request<Payload = GetAvailableGifts, Err = Self::Err>;

    /// For Telegram documentation see [`GetAvailableGifts`].
    fn get_available_gifts(&self) -> Self::GetAvailableGifts;

    type SendGift: Request<Payload = SendGift, Err = Self::Err>;

    /// For Telegram documentation see [`SendGift`].
    fn send_gift(&self, user_id: UserId, gift_id: GiftId) -> Self::SendGift;

    type SendGiftChat: Request<Payload = SendGiftChat, Err = Self::Err>;

    /// For Telegram documentation see [`SendGiftChat`].
    fn send_gift_chat<C>(&self, chat_id: C, gift_id: GiftId) -> Self::SendGiftChat
    where
        C: Into<Recipient>;

    type GiftPremiumSubscription: Request<Payload = GiftPremiumSubscription, Err = Self::Err>;

    /// For Telegram documentation see [`GiftPremiumSubscription`].
    fn gift_premium_subscription(
        &self,
        user_id: UserId,
        month_count: u8,
        star_count: u32,
    ) -> Self::GiftPremiumSubscription;

    type VerifyUser: Request<Payload = VerifyUser, Err = Self::Err>;

    /// For Telegram documentation see [`VerifyUser`].
    fn verify_user(&self, user_id: UserId) -> Self::VerifyUser;

    type VerifyChat: Request<Payload = VerifyChat, Err = Self::Err>;

    /// For Telegram documentation see [`VerifyChat`].
    fn verify_chat<C>(&self, chat_id: C) -> Self::VerifyChat
    where
        C: Into<Recipient>;

    type RemoveUserVerification: Request<Payload = RemoveUserVerification, Err = Self::Err>;

    /// For Telegram documentation see [`RemoveUserVerification`].
    fn remove_user_verification(&self, user_id: UserId) -> Self::RemoveUserVerification;

    type RemoveChatVerification: Request<Payload = RemoveChatVerification, Err = Self::Err>;

    /// For Telegram documentation see [`RemoveChatVerification`].
    fn remove_chat_verification<C>(&self, chat_id: C) -> Self::RemoveChatVerification
    where
        C: Into<Recipient>;

    type ReadBusinessMessage: Request<Payload = ReadBusinessMessage, Err = Self::Err>;

    /// For Telegram documentation see [`ReadBusinessMessage`].
    fn read_business_message<C>(
        &self,
        business_connection_id: BusinessConnectionId,
        chat_id: C,
        message_id: MessageId,
    ) -> Self::ReadBusinessMessage
    where
        C: Into<ChatId>;

    type DeleteBusinessMessages: Request<Payload = DeleteBusinessMessages, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteBusinessMessages`].
    fn delete_business_messages<M>(
        &self,
        business_connection_id: BusinessConnectionId,
        message_ids: M,
    ) -> Self::DeleteBusinessMessages
    where
        M: IntoIterator<Item = MessageId>;

    type SetBusinessAccountName: Request<Payload = SetBusinessAccountName, Err = Self::Err>;

    /// For Telegram documentation see [`SetBusinessAccountName`].
    fn set_business_account_name<F>(
        &self,
        business_connection_id: BusinessConnectionId,
        first_name: F,
    ) -> Self::SetBusinessAccountName
    where
        F: Into<String>;

    type SetBusinessAccountUsername: Request<Payload = SetBusinessAccountUsername, Err = Self::Err>;

    /// For Telegram documentation see [`SetBusinessAccountUsername`].
    fn set_business_account_username(
        &self,
        business_connection_id: BusinessConnectionId,
    ) -> Self::SetBusinessAccountUsername;

    type SetBusinessAccountBio: Request<Payload = SetBusinessAccountBio, Err = Self::Err>;

    /// For Telegram documentation see [`SetBusinessAccountBio`].
    fn set_business_account_bio(
        &self,
        business_connection_id: BusinessConnectionId,
    ) -> Self::SetBusinessAccountBio;

    type SetBusinessAccountProfilePhoto: Request<
        Payload = SetBusinessAccountProfilePhoto,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`SetBusinessAccountProfilePhoto`].
    fn set_business_account_profile_photo(
        &self,
        business_connection_id: BusinessConnectionId,
        photo: InputProfilePhoto,
    ) -> Self::SetBusinessAccountProfilePhoto;

    type RemoveBusinessAccountProfilePhoto: Request<
        Payload = RemoveBusinessAccountProfilePhoto,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`RemoveBusinessAccountProfilePhoto`].
    fn remove_business_account_profile_photo(
        &self,
        business_connection_id: BusinessConnectionId,
    ) -> Self::RemoveBusinessAccountProfilePhoto;

    type SetBusinessAccountGiftSettings: Request<
        Payload = SetBusinessAccountGiftSettings,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`SetBusinessAccountGiftSettings`].
    fn set_business_account_gift_settings(
        &self,
        business_connection_id: BusinessConnectionId,
        show_gift_button: bool,
        accepted_gift_types: AcceptedGiftTypes,
    ) -> Self::SetBusinessAccountGiftSettings;

    type GetBusinessAccountStarBalance: Request<
        Payload = GetBusinessAccountStarBalance,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`GetBusinessAccountStarBalance`].
    fn get_business_account_star_balance(
        &self,
        business_connection_id: BusinessConnectionId,
    ) -> Self::GetBusinessAccountStarBalance;

    type TransferBusinessAccountStars: Request<
        Payload = TransferBusinessAccountStars,
        Err = Self::Err,
    >;

    /// For Telegram documentation see [`TransferBusinessAccountStars`].
    fn transfer_business_account_stars(
        &self,
        business_connection_id: BusinessConnectionId,
        star_count: u32,
    ) -> Self::TransferBusinessAccountStars;

    type GetBusinessAccountGifts: Request<Payload = GetBusinessAccountGifts, Err = Self::Err>;

    /// For Telegram documentation see [`GetBusinessAccountGifts`].
    fn get_business_account_gifts(
        &self,
        business_connection_id: BusinessConnectionId,
    ) -> Self::GetBusinessAccountGifts;

    type ConvertGiftToStars: Request<Payload = ConvertGiftToStars, Err = Self::Err>;

    /// For Telegram documentation see [`ConvertGiftToStars`].
    fn convert_gift_to_stars(
        &self,
        business_connection_id: BusinessConnectionId,
        owned_gift_id: OwnedGiftId,
    ) -> Self::ConvertGiftToStars;

    type UpgradeGift: Request<Payload = UpgradeGift, Err = Self::Err>;

    /// For Telegram documentation see [`UpgradeGift`].
    fn upgrade_gift(
        &self,
        business_connection_id: BusinessConnectionId,
        owned_gift_id: OwnedGiftId,
    ) -> Self::UpgradeGift;

    type TransferGift: Request<Payload = TransferGift, Err = Self::Err>;

    /// For Telegram documentation see [`TransferGift`].
    fn transfer_gift<N>(
        &self,
        business_connection_id: BusinessConnectionId,
        owned_gift_id: OwnedGiftId,
        new_owner_chat_id: N,
    ) -> Self::TransferGift
    where
        N: Into<ChatId>;

    type PostStory: Request<Payload = PostStory, Err = Self::Err>;

    /// For Telegram documentation see [`PostStory`].
    fn post_story(
        &self,
        business_connection_id: BusinessConnectionId,
        content: InputStoryContent,
        active_period: Seconds,
    ) -> Self::PostStory;

    type EditStory: Request<Payload = EditStory, Err = Self::Err>;

    /// For Telegram documentation see [`EditStory`].
    fn edit_story(
        &self,
        business_connection_id: BusinessConnectionId,
        story_id: StoryId,
        content: InputStoryContent,
    ) -> Self::EditStory;

    type DeleteStory: Request<Payload = DeleteStory, Err = Self::Err>;

    /// For Telegram documentation see [`DeleteStory`].
    fn delete_story(
        &self,
        business_connection_id: BusinessConnectionId,
        story_id: StoryId,
    ) -> Self::DeleteStory;

    type SendInvoice: Request<Payload = SendInvoice, Err = Self::Err>;

    /// For Telegram documentation see [`SendInvoice`].
    fn send_invoice<Ch, T, D, Pa, C, P>(
        &self,
        chat_id: Ch,
        title: T,
        description: D,
        payload: Pa,
        currency: C,
        prices: P,
    ) -> Self::SendInvoice
    where
        Ch: Into<Recipient>,
        T: Into<String>,
        D: Into<String>,
        Pa: Into<String>,
        C: Into<String>,
        P: IntoIterator<Item = LabeledPrice>;

    type CreateInvoiceLink: Request<Payload = CreateInvoiceLink, Err = Self::Err>;

    /// For Telegram documentation see [`CreateInvoiceLink`].
    fn create_invoice_link<T, D, Pa, C, P>(
        &self,
        title: T,
        description: D,
        payload: Pa,
        currency: C,
        prices: P,
    ) -> Self::CreateInvoiceLink
    where
        T: Into<String>,
        D: Into<String>,
        Pa: Into<String>,
        C: Into<String>,
        P: IntoIterator<Item = LabeledPrice>;

    type AnswerShippingQuery: Request<Payload = AnswerShippingQuery, Err = Self::Err>;

    /// For Telegram documentation see [`AnswerShippingQuery`].
    fn answer_shipping_query(
        &self,
        shipping_query_id: ShippingQueryId,
        ok: bool,
    ) -> Self::AnswerShippingQuery;

    type AnswerPreCheckoutQuery: Request<Payload = AnswerPreCheckoutQuery, Err = Self::Err>;

    /// For Telegram documentation see [`AnswerPreCheckoutQuery`].
    fn answer_pre_checkout_query(
        &self,
        pre_checkout_query_id: PreCheckoutQueryId,
        ok: bool,
    ) -> Self::AnswerPreCheckoutQuery;

    type GetMyStarBalance: Request<Payload = GetMyStarBalance, Err = Self::Err>;

    /// For Telegram documentation see [`GetMyStarBalance`].
    fn get_my_star_balance(&self) -> Self::GetMyStarBalance;

    type GetStarTransactions: Request<Payload = GetStarTransactions, Err = Self::Err>;

    /// For Telegram documentation see [`GetStarTransactions`].
    fn get_star_transactions(&self) -> Self::GetStarTransactions;

    type RefundStarPayment: Request<Payload = RefundStarPayment, Err = Self::Err>;

    /// For Telegram documentation see [`RefundStarPayment`].
    fn refund_star_payment(
        &self,
        user_id: UserId,
        telegram_payment_charge_id: TelegramTransactionId,
    ) -> Self::RefundStarPayment;

    type EditUserStarSubscription: Request<Payload = EditUserStarSubscription, Err = Self::Err>;

    /// For Telegram documentation see [`EditUserStarSubscription`].
    fn edit_user_star_subscription(
        &self,
        user_id: UserId,
        telegram_payment_charge_id: TelegramTransactionId,
        is_canceled: bool,
    ) -> Self::EditUserStarSubscription;

    type SetPassportDataErrors: Request<Payload = SetPassportDataErrors, Err = Self::Err>;

    /// For Telegram documentation see [`SetPassportDataErrors`].
    fn set_passport_data_errors<E>(
        &self,
        user_id: UserId,
        errors: E,
    ) -> Self::SetPassportDataErrors
    where
        E: IntoIterator<Item = PassportElementError>;

    type SendGame: Request<Payload = SendGame, Err = Self::Err>;

    /// For Telegram documentation see [`SendGame`].
    fn send_game<C, G>(&self, chat_id: C, game_short_name: G) -> Self::SendGame
    where
        C: Into<ChatId>,
        G: Into<String>;

    type SetGameScore: Request<Payload = SetGameScore, Err = Self::Err>;

    /// For Telegram documentation see [`SetGameScore`].
    fn set_game_score(
        &self,
        user_id: UserId,
        score: u64,
        chat_id: u32,
        message_id: MessageId,
    ) -> Self::SetGameScore;

    type SetGameScoreInline: Request<Payload = SetGameScoreInline, Err = Self::Err>;

    /// For Telegram documentation see [`SetGameScoreInline`].
    fn set_game_score_inline<I>(
        &self,
        user_id: UserId,
        score: u64,
        inline_message_id: I,
    ) -> Self::SetGameScoreInline
    where
        I: Into<String>;

    type GetGameHighScores: Request<Payload = GetGameHighScores, Err = Self::Err>;

    /// For Telegram documentation see [`GetGameHighScores`].
    fn get_game_high_scores<T>(&self, user_id: UserId, target: T) -> Self::GetGameHighScores
    where
        T: Into<TargetMessage>;
    // END BLOCK requester_methods
}

macro_rules! fty {
    ($T:ident) => {
        B::$T
    };
}

macro_rules! fwd_deref {
    ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
        core::ops::Deref::deref($this).$m($($arg),*)
    };
}

macro_rules! forward_all {
    ($body:ident, $ty:ident) => {
        requester_forward! {
            get_me,
            log_out,
            close,
            get_updates,
            set_webhook,
            delete_webhook,
            get_webhook_info,
            forward_message,
            forward_messages,
            copy_message,
            copy_messages,
            send_message,
            send_photo,
            send_audio,
            send_document,
            send_video,
            send_animation,
            send_voice,
            send_video_note,
            send_paid_media,
            send_media_group,
            send_location,
            edit_message_live_location,
            edit_message_live_location_inline,
            stop_message_live_location,
            stop_message_live_location_inline,
            edit_message_checklist,
            send_venue,
            send_contact,
            send_poll,
            send_checklist,
            send_dice,
            send_chat_action,
            set_message_reaction,
            get_user_profile_photos,
            set_user_emoji_status,
            get_file,
            kick_chat_member,
            ban_chat_member,
            unban_chat_member,
            restrict_chat_member,
            promote_chat_member,
            set_chat_administrator_custom_title,
            ban_chat_sender_chat,
            unban_chat_sender_chat,
            set_chat_permissions,
            export_chat_invite_link,
            create_chat_invite_link,
            edit_chat_invite_link,
            create_chat_subscription_invite_link,
            edit_chat_subscription_invite_link,
            revoke_chat_invite_link,
            set_chat_photo,
            delete_chat_photo,
            set_chat_title,
            set_chat_description,
            pin_chat_message,
            unpin_chat_message,
            unpin_all_chat_messages,
            leave_chat,
            get_chat,
            get_chat_administrators,
            get_chat_members_count,
            get_chat_member_count,
            get_chat_member,
            set_chat_sticker_set,
            delete_chat_sticker_set,
            get_forum_topic_icon_stickers,
            create_forum_topic,
            edit_forum_topic,
            close_forum_topic,
            reopen_forum_topic,
            delete_forum_topic,
            unpin_all_forum_topic_messages,
            edit_general_forum_topic,
            close_general_forum_topic,
            reopen_general_forum_topic,
            hide_general_forum_topic,
            unhide_general_forum_topic,
            unpin_all_general_forum_topic_messages,
            answer_callback_query,
            get_user_chat_boosts,
            set_my_commands,
            get_business_connection,
            get_my_commands,
            set_my_name,
            get_my_name,
            set_my_description,
            get_my_description,
            set_my_short_description,
            get_my_short_description,
            set_chat_menu_button,
            get_chat_menu_button,
            set_my_default_administrator_rights,
            get_my_default_administrator_rights,
            delete_my_commands,
            answer_inline_query,
            answer_web_app_query,
            save_prepared_inline_message,
            edit_message_text,
            edit_message_text_inline,
            edit_message_caption,
            edit_message_caption_inline,
            edit_message_media,
            edit_message_media_inline,
            edit_message_reply_markup,
            edit_message_reply_markup_inline,
            stop_poll,
            delete_message,
            delete_messages,
            send_sticker,
            get_sticker_set,
            get_custom_emoji_stickers,
            upload_sticker_file,
            create_new_sticker_set,
            add_sticker_to_set,
            set_sticker_position_in_set,
            delete_sticker_from_set,
            replace_sticker_in_set,
            set_sticker_set_thumbnail,
            set_custom_emoji_sticker_set_thumbnail,
            set_sticker_set_title,
            delete_sticker_set,
            set_sticker_emoji_list,
            set_sticker_keywords,
            set_sticker_mask_position,
            get_available_gifts,
            send_gift,
            send_gift_chat,
            gift_premium_subscription,
            verify_user,
            verify_chat,
            remove_user_verification,
            remove_chat_verification,
            read_business_message,
            delete_business_messages,
            set_business_account_name,
            set_business_account_username,
            set_business_account_bio,
            set_business_account_profile_photo,
            remove_business_account_profile_photo,
            set_business_account_gift_settings,
            get_business_account_star_balance,
            transfer_business_account_stars,
            get_business_account_gifts,
            convert_gift_to_stars,
            upgrade_gift,
            transfer_gift,
            post_story,
            edit_story,
            delete_story,
            send_invoice,
            create_invoice_link,
            answer_shipping_query,
            answer_pre_checkout_query,
            get_my_star_balance,
            get_star_transactions,
            refund_star_payment,
            edit_user_star_subscription,
            set_passport_data_errors,
            send_game,
            set_game_score,
            set_game_score_inline,
            get_game_high_scores,
            approve_chat_join_request,
            decline_chat_join_request
            => $body, $ty
        }
    };
    () => {
        forward_all! { fwd_deref, fty }
    };
}

impl<B> Requester for &B
where
    B: Requester,
{
    type Err = B::Err;

    forward_all! {}
}

impl<B> Requester for &mut B
where
    B: Requester,
{
    type Err = B::Err;

    forward_all! {}
}

impl<B> Requester for Box<B>
where
    B: Requester,
{
    type Err = B::Err;

    forward_all! {}
}

impl<B> Requester for std::sync::Arc<B>
where
    B: Requester,
{
    type Err = B::Err;

    forward_all! {}
}

impl<B> Requester for std::rc::Rc<B>
where
    B: Requester,
{
    type Err = B::Err;

    forward_all! {}
}

// macro_rules! fty_either {
//     ($T:ident) => {
//         either::Either<LR::$T, RR::$T>
//     };
// }

// macro_rules! fwd_either {
//     ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
//         match ($this) {
//             either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)),
//             either::Either::Right(r) =>
// either::Either::Right(r.$m($($arg),*)),         }
//     };
// }

// impl<LR, RR> Requester for either::Either<LR, RR>
// where
//     LR: Requester,
//     RR: Requester<Err = LR::Err>,
// {
//     type Err = LR::Err;

//     forward_all! { fwd_either, fty_either }
// }

#[test]
// waffle: efficiency is not important here, and I don't want to rewrite this
#[allow(clippy::format_collect)]
fn codegen_requester_methods() {
    use crate::codegen::{
        add_hidden_preamble,
        convert::{convert_for, Convert},
        ensure_file_contents, min_prefix, project_root, reformat, replace_block,
        schema::{self, Type},
        to_uppercase,
    };
    use indexmap::IndexMap;
    use itertools::Itertools;

    let schema = schema::get();

    let methods = schema
        .methods
        .iter()
        .map(|m| {
            let mut convert_params = m
                .params
                .iter()
                .filter(|p| !matches!(p.ty, Type::Option(_)))
                .map(|p| (&p.name, convert_for(&p.ty)))
                .filter(|(_, c)| !matches!(c, Convert::Id(_)))
                .map(|(name, _)| &**name)
                .collect::<Vec<_>>();

            convert_params.sort_unstable();

            let prefixes: IndexMap<_, _> = convert_params
                .iter()
                .copied()
                // Workaround to output the last type as the first letter
                .chain(["\0"])
                .tuple_windows()
                .map(|(l, r)| (l, min_prefix(l, r)))
                .collect();

            let args = m
                .params
                .iter()
                .filter(|p| !matches!(p.ty, schema::Type::Option(_)))
                .map(|p| match prefixes.get(&*p.name) {
                    Some(prefix) => format!("{}: {}", p.name, to_uppercase(prefix)),
                    None => format!("{}: {}", p.name, p.ty),
                })
                .join(", ");

            let generics = m
                .params
                .iter()
                .flat_map(|p| prefixes.get(&*p.name))
                .copied()
                .map(to_uppercase)
                .join(", ");
            let where_clause = m
                .params
                .iter()
                .filter(|p| !matches!(p.ty, Type::Option(_)))
                .flat_map(|p| match convert_for(&p.ty) {
                    Convert::Id(_) => None,
                    Convert::Into(ty) => {
                        Some(format!("{}: Into<{}>", &to_uppercase(prefixes[&*p.name]), ty))
                    }
                    Convert::Collect(ty) => Some(format!(
                        "{}: IntoIterator<Item = {}>",
                        &to_uppercase(prefixes[&*p.name]),
                        ty
                    )),
                })
                .join(",\n        ");

            let generics =
                if generics.is_empty() { String::from("") } else { format!("<{generics}>") };

            let where_clause = if where_clause.is_empty() {
                String::from("")
            } else {
                format!(" where {where_clause}")
            };

            format!(
                "
type {Method}: Request<Payload = {Method}, Err = Self::Err>;

/// For Telegram documentation see [`{Method}`].
fn {method} {generics} (&self, {args}) -> Self::{Method}{where_clause};
            ",
                Method = m.names.1,
                method = m.names.2,
            )
        })
        .collect::<String>();

    let path = project_root().join("src/requests/requester.rs");

    ensure_file_contents(
        &path,
        &reformat(replace_block(
            &path,
            "requester_methods",
            &add_hidden_preamble("codegen_requester_methods", methods),
        )),
    );
}
